package com.laomou.poker.rule;

import java.util.List;

import com.java.rapid.Condition2;
import com.java.rapid.Condition3;
import com.java.rapid.Function;
import com.java.rapid.Return;
import com.java.rapid.list.raList;
import com.java.rapid.list.raList.ListObservable;
import com.java.rapid.list.raListGroup;
import com.java.rapid.list.raListGroup.ListGroupObservable;
import com.laomou.poker.Poker;
import com.laomou.poker.PokerGroup;

public abstract class AbsPokerRule implements IPokerRule {
    @Override
    public boolean hasBigPoker(PokerGroup playerPg, PokerGroup pg, List<PokerGroup> list) {
        return false;
    }

    /**
     * 从大到小排序
     *
     * @param pokerGroup
     * @return ListObservable<Poker>
     */
    protected final ListObservable<Poker> bigtosmall(PokerGroup pokerGroup) {
        return raList.from(pokerGroup.get()).sort(new Condition2<Poker>() {

            @Override
            public boolean apply(Poker condition1, Poker condition2) {
                return condition1.value() < condition2.value();
            }
        });
    }

    /**
     * 从小到大排序
     *
     * @param pokerGroup
     * @return ListObservable<Poker>
     */
    protected final ListObservable<Poker> smalltobig(PokerGroup pokerGroup) {
        return raList.from(pokerGroup.get()).sort(new Condition2<Poker>() {

            @Override
            public boolean apply(Poker condition1, Poker condition2) {
                return condition1.value() > condition2.value();
            }
        });
    }

    private boolean isSameList(List<Poker> list) {
        int size = list.size();
        boolean isSame = false;
        for (int i = 0; i < size - 1; i++) {
            if (list.get(i).value() == list.get(i + 1).value()) {
                isSame = true;
            } else {
                isSame = false;
                break;
            }
        }
        return isSame;
    }

    private boolean isSameColorList(List<Poker> list) {
        int size = list.size();
        boolean isSame = false;
        for (int i = 0; i < size - 1; i++) {
            String cname1 = list.get(i).colorName();
            String cname2 = list.get(i + 1).colorName();
            if (cname1.equals(cname2)) {
                isSame = true;
            } else {
                isSame = false;
                break;
            }
        }
        return isSame;
    }

    private boolean isStraightList(List<Poker> list) {
        int size = list.size();
        boolean isStraight = false;
        for (int i = 0; i < size - 1; i++) {
            if (list.get(i + 1).value() - 1 == list.get(i).value()) {
                isStraight = true;
            } else {
                isStraight = false;
                break;
            }
        }
        return isStraight;
    }

    protected final ListGroupObservable<Poker> getSame(PokerGroup pokerGroup, int count) {
        return raListGroup.from1(pokerGroup.get()).select(count)
                .filter(new Condition3<Poker>() {

                    @Override
                    public boolean apply(List<Poker> t) {
                        return isSameList(t);
                    }
                });
    }

    /**
     * 判断有几个牌是否相等
     *
     * @param pokerGroup
     * @param count
     * @return boolean
     */
    protected final boolean hasSame(PokerGroup pokerGroup, int count) {
        if (count == 1) {
            return true;
        }
        List<List<Poker>> lists = raListGroup.from1(pokerGroup.get())
                .select(count).filter(new Condition3<Poker>() {

                    @Override
                    public boolean apply(List<Poker> t) {
                        return isSameList(t);
                    }
                }).toListGroup();
        boolean ret = lists.size() >= 1;
        if (ret) {
            int value = countLists(lists);
            pokerGroup.setValue(value);
        }
        return ret;
    }

    /**
     * 判断有几个花色牌是否相等
     *
     * @param pokerGroup
     * @param count
     * @return boolean
     */
    protected final boolean hasSameColor(PokerGroup pokerGroup, int count) {
        return raListGroup.from1(pokerGroup.get()).select(count)
                .filter(new Condition3<Poker>() {

                    @Override
                    public boolean apply(List<Poker> t) {
                        return isSameColorList(t);
                    }
                }).toListGroup().size() >= 1;
    }

    /**
     * 判断几个牌是否相等
     *
     * @param pokerGroup
     * @param count
     * @return boolean
     */
    protected final boolean isSame(PokerGroup pokerGroup) {
        if (pokerGroup.size() == 1) {
            return true;
        }
        return isSameList(pokerGroup.get());
    }

    protected final boolean isStraight(List<Poker> list) {
        int count = list.size();
        return raListGroup.from1(list).select(count)
                .filter(new Condition3<Poker>() {

                    @Override
                    public boolean apply(List<Poker> t) {
                        return isStraightList(t);
                    }
                }).toListGroup().size() == 1;
    }

    /**
     * 判断是否顺子
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isStraight(PokerGroup pokerGroup) {
        if (pokerGroup.size() < 5) {
            return false;
        }
        List<Poker> list = smalltobig(pokerGroup).toList();
        return isStraight(list);
    }

    /**
     * 判断是否双顺子
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isTwoStraight(PokerGroup pokerGroup) {
        int size = pokerGroup.size();
        if (size < 6 || size % 2 != 0) {
            return false;
        }
        // 过滤二个相同牌的组合
        List<List<Poker>> lists = sameListGroup(pokerGroup, 2).toListGroup();
        // 只有一组二个相同牌
        int lsize = lists.size();
        if (lsize <= 1) {
            return false;
        }
        if (size / 2 != lsize) {
            return false;
        }
        // 转换成单个数组
        List<Poker> list = sortToList(lists).toList();
        return isStraight(list);
    }

    /**
     * 判断是否三顺子
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isThreeStraight(PokerGroup pokerGroup) {
        int size = pokerGroup.size();
        if (size < 6 || size % 3 != 0) {
            return false;
        }
        // 过滤三个相同牌的组合
        List<List<Poker>> lists = sameListGroup(pokerGroup, 3).toListGroup();
        // 只有一组三个相同牌
        int lsize = lists.size();
        if (lsize < 1) {
            return false;
        }
        if (size / 3 != lsize) {
            return false;
        }
        // 转换成单个数组
        List<Poker> list = sortToList(lists).toList();
        return isStraight(list);
    }

    /**
     * 判断是否连三带单牌
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isThreeLinkOne(PokerGroup pokerGroup) {
        int size = pokerGroup.size();
        if (size != 4) {
            return false;
        }
        return hasSame(pokerGroup, 3);
    }

    /**
     * 判断是否四带二牌
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isFourLinkTwo(PokerGroup pokerGroup) {
        int size = pokerGroup.size();
        if (size != 6) {
            return false;
        }
        return hasSame(pokerGroup, 4);
    }

    private final ListGroupObservable<Poker> sameListGroup(
            PokerGroup pokerGroup, int count) {
        return raListGroup.from1(pokerGroup.get()).select(count)
                .filter(new Condition3<Poker>() {

                    @Override
                    public boolean apply(List<Poker> t) {
                        return isSameList(t);
                    }
                });
    }

    private final ListObservable<Poker> sortToList(List<List<Poker>> lists) {
        return raList.from(lists).map(new Function<List<Poker>, Poker>() {

            @Override
            public Poker apply(List<Poker> input) {
                return input.get(0);
            }
        }).sort(new Condition2<Poker>() {

            @Override
            public boolean apply(Poker t1, Poker t2) {
                return t1.value() > t2.value();
            }
        });
    }

    private final int countLists(List<List<Poker>> lists) {
        return raList.from(lists).map(new Function<List<Poker>, Poker>() {

            @Override
            public Poker apply(List<Poker> input) {
                return input.get(0);
            }
        }).count(new Return<Poker, Integer>() {

            @Override
            public Integer result(Poker t) {
                return t.value();
            }
        });
    }

    private final int countList(List<Poker> list) {
        return raList.from(list).count(new Return<Poker, Integer>() {

            @Override
            public Integer result(Poker t) {
                return t.value();
            }
        });
    }

    /**
     * 判断是否四飞机
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isFourFly(PokerGroup pokerGroup) {
        int size = pokerGroup.size();
        if (size < 6) {
            return false;
        }
        // 过滤三个相同牌的组合
        List<List<Poker>> lists = sameListGroup(pokerGroup, 4).toListGroup();
        // 剩余单牌个数
        int lsize = lists.size();
        if (size != 6 * lsize) {
            return false;
        }
        // 只有一组四个相同牌
        if (lsize == 1) {
            return false;
        }
        // 转换成单个数组
        List<Poker> list = sortToList(lists).toList();
        boolean ret = isStraight(list);
        if (ret) {
            int value = countList(list);
            pokerGroup.setValue(value);
        }
        return ret;
    }

    /**
     * 判断是否三飞机
     *
     * @param pokerGroup
     * @return boolean
     */
    protected final boolean isThreeFly(PokerGroup pokerGroup) {
        int size = pokerGroup.size();
        if (size < 6) {
            return false;
        }
        // 过滤三个相同牌的组合
        List<List<Poker>> lists = sameListGroup(pokerGroup, 3).toListGroup();
        // 剩余单牌个数
        int lsize = lists.size();
        if (lsize != size - (lsize * 3)) {
            return false;
        }
        // 只有一组三个相同牌
        if (lsize == 1) {
            return false;
        }
        // 转换成单个数组
        List<Poker> list = sortToList(lists).toList();
        boolean ret = isStraight(list);
        if (ret) {
            int value = countList(list);
            pokerGroup.setValue(value);
        }
        return ret;
    }
}
